package utils

import (
	"fmt"
	"reflect"
	"strings"
)

func IsInArray[T string | byte | int | int64 | uint | uint64 | float32 | float64](value T, array []T) bool {
	if len(array) == 0 {
		return false
	}
	for _, item := range array {
		if item == value {
			return true
		}
	}
	return false
}

func ArrayToString[T string | byte | int | int64 | uint | uint64 | float32 | float64](elems []T, sep string) string {
	if len(elems) == 0 {
		return ""
	}
	var builder strings.Builder
	for _, item := range elems {
		if builder.Len() > 0 && len(sep) > 0 {
			builder.WriteString(sep)
		}
		builder.WriteString(fmt.Sprint(item))
	}
	return builder.String()
}

func ArrayEqual[T string | byte | int | int64 | uint | uint64 | float32 | float64](a, b []T) bool {
	if a == nil && b == nil {
		return true
	}
	if (a == nil) != (b == nil) {
		return false
	}
	if len(a) != len(b) {
		return false
	}
	for i := range a {
		if a[i] != b[i] {
			return false
		}
	}
	return true
}

// ArrayIntersection 求两个数组的交集
func ArrayIntersection[T string | byte | int | int64 | uint | uint64 | float32 | float64](a, b []T) (inter []T) {
	if len(a) == 0 || len(b) == 0 {
		return []T{}
	}
	var result = make([]T, 0)
	var aMap = make(map[T]bool)
	for _, aItem := range a {
		aMap[aItem] = true
	}
	for _, bItem := range b {
		if aMap[bItem] {
			result = append(result, bItem)
		}
	}
	return result
}

func GetFieldIntArray[T any](array []T, fieldName string) []int {
	var list = make([]int, 0)
	for _, elem := range array {
		field := reflect.ValueOf(elem).FieldByName(fieldName)
		if field.IsValid() && field.Kind() == reflect.Int {
			var fieldValue = reflect.ValueOf(elem).FieldByName(fieldName).Int()
			list = append(list, int(fieldValue))
		}
	}
	return list
}

func GetFieldInt64Array[T any](array []T, fieldName string) []int64 {
	var list = make([]int64, 0)
	for _, elem := range array {
		field := reflect.ValueOf(elem).FieldByName(fieldName)
		if field.IsValid() && field.Kind() == reflect.Int64 {
			var fieldValue = reflect.ValueOf(elem).FieldByName(fieldName).Int()
			list = append(list, fieldValue)
		}
	}
	return list
}

func GetFieldFloat32Array[T any](array []T, fieldName string) []float32 {
	var list = make([]float32, 0)
	for _, elem := range array {
		field := reflect.ValueOf(elem).FieldByName(fieldName)
		if field.IsValid() && field.Kind() == reflect.Float32 {
			var fieldValue = reflect.ValueOf(elem).FieldByName(fieldName).Float()
			list = append(list, float32(fieldValue))
		}
	}
	return list
}

func GetFieldFloat64Array[T any](array []T, fieldName string) []float64 {
	var list = make([]float64, 0)
	for _, elem := range array {
		field := reflect.ValueOf(elem).FieldByName(fieldName)
		if field.IsValid() && field.Kind() == reflect.Float64 {
			var fieldValue = reflect.ValueOf(elem).FieldByName(fieldName).Float()
			list = append(list, fieldValue)
		}
	}
	return list
}

func GetFieldStringArray[T any](array []T, fieldName string) []string {
	var list = make([]string, 0)
	for _, elem := range array {
		values := reflect.ValueOf(elem)
		field := values.FieldByName(fieldName)
		if field.IsValid() && field.Kind() == reflect.String {
			var fieldValue = reflect.ValueOf(elem).FieldByName(fieldName).String()
			list = append(list, fieldValue)
		}
	}
	return list
}

func MakeDistinctArray[T string | byte | int | int64 | uint | uint64 | float32 | float64](array []T) []T {
	if len(array) == 0 {
		return array
	}
	var result = make([]T, 0)
	var tempMap = make(map[T]bool)
	for _, item := range array {
		if _, ok := tempMap[item]; ok {
			continue
		}
		result = append(result, item)
		tempMap[item] = true
	}
	return result
}
